package cn.jinbyte.core.utils;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.jinbyte.core.exception.SysException;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;

/**
 * SM4对称加密
 *
 * @author jinty
 * @since 2024/4/26
 */
@Slf4j
@UtilityClass
@SuppressWarnings("unused")
public class Sm4Utils {

    /**
     * SM4加密字符串
     *
     * @param content 需要加密的内容
     * @return 加密后的十六进制字符串
     */
    public static String encrypt(String content, String key) {
        if (StringUtils.isBlank(content)) {
            return content;
        }
        checkKeyLength(key);
        try {
            SymmetricCrypto SM4 = SmUtil.sm4(key.getBytes(StandardCharsets.UTF_8));
            return SM4.encryptHex(content);
        } catch (Exception e) {
            log.error("数据加密失败", e);
            throw new SysException("数据加密失败");
        }
    }

    /**
     * SM4解密字符串
     *
     * @param content 需要解密的内容
     * @return 解密后的字符串
     */
    public static String decrypt(String content, String key) {
        if (StringUtils.isBlank(content)) {
            return content;
        }
        checkKeyLength(key);
        try {
            SymmetricCrypto SM4 = SmUtil.sm4(key.getBytes(StandardCharsets.UTF_8));
            return SM4.decryptStr(content, CharsetUtil.CHARSET_UTF_8);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new SysException("数据解密失败");
        }
    }

    /**
     * 安全解密字符串，若解密失败则返回原始内容
     *
     * @param content   需要解密的内容
     * @param nullToStr 如果解密结果为空则返回该值
     * @return 解密后的字符串或默认值
     */
    public static String decryptOrDefault(String content, String nullToStr, String key) {
        if (StringUtils.isBlank(content)) {
            throw new SysException("解密参数不能为空");
        }
        String str;
        try {
            str = decrypt(content, key);
        } catch (Exception e) {
            // 若解密报错，返回原字符串
            log.error(e.getMessage());
            str = content;
        }
        return StringUtils.isEmpty(str) ? nullToStr : str;

    }

    public static void checkKeyLength(String key) {
        if (key == null || key.getBytes(StandardCharsets.UTF_8).length != 16) {
            throw new IllegalArgumentException("SM4密钥必须为16字节");
        }
    }

}
